#include <QVariant>
#include <QDebug>
#include <QMetaObject>
#include <QMetaProperty>
#include <QDataStream>
#include <QFile>
#include "ConfigDataModel.h"
#include "Items.h"

#define MAGIC_NUMBER 0xA1B2C3D4
#define CONFIG_DATA_VERSION 1

ConfigDataModel::ConfigDataModel(QObject *parent) : QObject(parent)
{

}

bool ConfigDataModel::readFromFile(QString filePath)
{
    bool ret = true;
    QFile file(filePath);
    ret = file.open(QIODevice::ReadOnly);
    if (ret)
    {
        QDataStream in(&file);
        in.setVersion(QDataStream::Qt_5_6);
        quint32 magicNumber = 0;
        quint32 configDataVersion = 0;
        in >> magicNumber;
        in >> configDataVersion;
        if (magicNumber != MAGIC_NUMBER || configDataVersion != CONFIG_DATA_VERSION)
        {
            qWarning() << "版本不匹配";
            ret = false;
            return ret;
        }

        in >> *this;
    }
    return ret;
}

bool ConfigDataModel::writeToFile(QString filePath)
{
    bool ret = true;
    QFile file(filePath);
    ret = file.open(QIODevice::WriteOnly);
    if (ret)
    {
        QDataStream out(&file);
        out.setVersion(QDataStream::Qt_5_6);
        out << quint32(MAGIC_NUMBER);
        out << quint32(CONFIG_DATA_VERSION);
        out << *this;
    }
    return ret;
}

ConfigDataModel::~ConfigDataModel()
{
    const QMetaObject *obj = this->metaObject();
    for (int i = obj->propertyOffset(); i < obj->propertyCount(); i++)
    {
        QMetaProperty property = obj->property(i);
        if (property.read(this).canConvert<ConfigItem*>())
        {
            ConfigItem *item = property.read(this).value<ConfigItem*>();
            if (item != nullptr)
            {
                item->deleteLater();
            }
            property.write(this, QVariant::fromValue<ConfigItem*>(nullptr));
        }
        else if (property.read(this).canConvert<ConfigDataModel*>())
        {
            ConfigDataModel *model = property.read(this).value<ConfigDataModel*>();
            if (model != nullptr)
            {
                model->deleteLater();
            }
            property.write(this, QVariant::fromValue<ConfigDataModel*>(nullptr));
        }
    }
}


bool ConfigDataModel::ensureItemRegisterd()
{
    bool ret = true;
    const QMetaObject *obj = this->metaObject();
    for (int i = obj->propertyOffset(); i < obj->propertyCount(); i++)
    {
        QMetaProperty property = obj->property(i);
        if (property.read(this).canConvert<ConfigItem*>())
        {
            ConfigItem *item = property.read(this).value<ConfigItem*>();
            if (item == nullptr)
            {
                qWarning() << QString("ConfigItem(%1) %2 is pointed to null !").arg(property.typeName()).arg(property.name());
                ret = false;
            }
            else if (qobject_cast<ItemEnum*>(item) && !qobject_cast<ItemEnum*>(item)->getMetaEnum().isValid())
            {
                qWarning() << QString("ConfigItem(ItemEnum) %1 is not registered !").arg(property.name());
                ret = false;
            }
            else if (qobject_cast<ItemFlag*>(item) && !qobject_cast<ItemFlag*>(item)->getMetaEnum().isValid())
            {
                qWarning() << QString("ConfigItem(ItemFlag) %1 is not registered !").arg(property.name());
                ret = false;
            }
            // item->setObjectName(property.name());
        }
        else if (property.read(this).canConvert<ConfigDataModel*>())
        {
            ConfigDataModel *item = property.read(this).value<ConfigDataModel*>();
            if (item == nullptr)
            {
                qWarning() << QString("ConfigDataModel(%1) %2 is pointed to null !").arg(property.typeName()).arg(property.name());
                ret = false;
            }
        }


    }
    return ret;
}


QDataStream &operator<<(QDataStream &stream, const ConfigDataModel &model)
{
    stream << model.objectName();
    const QMetaObject *obj = model.metaObject();
    for (int i = obj->propertyOffset(); i < obj->propertyCount(); i++)
    {
        QMetaProperty property = obj->property(i);
        if (property.read(&model).canConvert<ConfigItem*>())
        {
            ConfigItem *item = property.read(&model).value<ConfigItem*>();
            if (item != nullptr)
            {
                stream << item->objectName();
                item->writeToData(stream);
            }
        }
        else if (property.read(&model).canConvert<ConfigDataModel*>())
        {
            ConfigDataModel *item = property.read(&model).value<ConfigDataModel*>();
            if (item != nullptr)
            {
                stream << *item;
            }
        }
    }
}

QDataStream &operator>>(QDataStream &stream, ConfigDataModel &model)
{
    while (!stream.atEnd())
    {
        QString name;
        stream >> name;
        QVariant ptr = model.property(name.toUtf8().data());
        if (ptr.isValid() && ptr.canConvert<ConfigItem*>())
        {
            ConfigItem *item = ptr.value<ConfigItem*>();
            item->readFromData(stream);
        }
        else if (ptr.isValid() && ptr.canConvert<ConfigDataModel*>())
        {
            ConfigDataModel *item = ptr.value<ConfigDataModel*>();
            stream >> *item;
        }
    }
}
